home *** CD-ROM | disk | FTP | other *** search
/ Greenhouse Effect Detection Expriment / NASA Greenhouse Effect Detection Expriment 1992 - Disc 2.iso / software / dos / cdf22pc / src / lib / vio.c < prev   
Encoding:
C/C++ Source or Header  |  1992-03-02  |  22.6 KB  |  723 lines

  1. /******************************************************************************
  2. *
  3. *  NSSDC/CDF                        Virtual STREAM_LF.
  4. *
  5. *  Version 4.0, 2-Mar-92, ST Systems (STX)
  6. *
  7. *  Modification history:
  8. *
  9. *   V1.0  22-Jan-91, J Love    Original version (developed for CDF V2.0).
  10. *   V2.0  12-Mar-91, J Love    All fixes to V1.x.  Modified vread and vwrite
  11. *                to buffer only when necessary.
  12. *   V3.0  14-May-91, J Love    Added caching (for CDF V2.1).
  13. *   V3.1  31-Jul-91, J Love    Added veof.  Added 'memmove' for UNIX.  Added
  14. *                "deq - default extension quantity" if VMS.
  15. *                Changed algorithm that looks for bufferN.
  16. *                Added number of CACHE buffers as a parameter
  17. *                specified in 'Vopen'.  Renamed functions to
  18. *                avoid collisions on SGi/IRIX.
  19. *   V3.2  15-Aug-91, J Love    Changed for IBM-PC/MS-DOS port.
  20. *   V4.0   2-Mar-92, J Love    IBM PC port/CDF V2.2.
  21. *
  22. ******************************************************************************/
  23.  
  24. #include "vio.h"
  25.  
  26. /******************************************************************************
  27. * Local function prototypes.
  28. ******************************************************************************/
  29.  
  30. #if defined(vms) | defined(__MSDOS__)
  31. long EXTENDfile (VFILE *, long);
  32. long ALLOCbuffer (VFILE *, long *);
  33. #endif
  34.  
  35. #if defined(unix)
  36. long EXTENDfile ();
  37. long ALLOCbuffer ();
  38. #endif
  39.  
  40. /******************************************************************************
  41. * Read from the file.
  42. * WARNING: This macro has a 'return' statement.
  43. ******************************************************************************/
  44.  
  45. #define READ(offset,buffer,itemsize,numitems,vfp,OnErrorReturn) { \
  46. int _try; \
  47. for (_try = 1; _try <= vioMAX_TRYs; _try++) { \
  48.    if (fseek(vfp->fp,offset,SEEK_SET) == EOF) { \
  49.      vfp->error = TRUE; \
  50.      return OnErrorReturn; \
  51.    } \
  52.    if (fread(buffer,itemsize,numitems,vfp->fp) == numitems) break; \
  53. } \
  54. if (_try > vioMAX_TRYs) { \
  55.   vfp->error = TRUE; \
  56.   return OnErrorReturn; \
  57. } \
  58. }
  59.  
  60. /******************************************************************************
  61. * Write to the file.
  62. * WARNING: This macro has a 'return' statement.
  63. ******************************************************************************/
  64.  
  65. #define WRITE(offset,buffer,itemsize,numitems,vfp,OnErrorReturn) { \
  66. int _try; \
  67. for (_try = 1; _try <= vioMAX_TRYs; _try++) { \
  68.    if (fseek(vfp->fp,offset,SEEK_SET) == EOF) { \
  69.      vfp->error = TRUE; \
  70.      return OnErrorReturn; \
  71.    } \
  72.    if (fwrite(buffer,itemsize,numitems,vfp->fp) == numitems) break; \
  73. } \
  74. if (_try > vioMAX_TRYs) { \
  75.   vfp->error = TRUE; \
  76.   return OnErrorReturn; \
  77. } \
  78. }
  79.  
  80. /******************************************************************************
  81. * Free memory allocated for a file.
  82. ******************************************************************************/
  83.  
  84. #define FREEvfp(vfp) { \
  85. long _bufferN; \
  86. if (vfp->CACHEblockN != NULL) free (vfp->CACHEblockN); \
  87. if (vfp->CACHEmodified != NULL) free (vfp->CACHEmodified); \
  88. if (vfp->CACHEaccessedAt != NULL) free (vfp->CACHEaccessedAt); \
  89. if (vfp->CACHEbuffers != NULL) { \
  90.   for (_bufferN = 0; _bufferN < vfp->nCACHEbuffers; _bufferN++) \
  91.      if (vfp->CACHEbuffers[_bufferN] != NULL) \
  92.        free (vfp->CACHEbuffers[_bufferN]); \
  93.   free (vfp->CACHEbuffers); \
  94. } \
  95. free (vfp); \
  96. }
  97.  
  98. /******************************************************************************
  99. * Check if a block is in the cache.
  100. ******************************************************************************/
  101.  
  102. #define CACHEbufferN(vfp,blockN,bufferN) { \
  103. long _bufferNt; \
  104. if (vfp->lastBufferNaccessed != -1) { \
  105.   if (vfp->CACHEblockN[vfp->lastBufferNaccessed] == blockN) \
  106.     bufferN = vfp->lastBufferNaccessed; \
  107.   else { \
  108.     bufferN = -1; \
  109.     for (_bufferNt = 0; _bufferNt < vfp->nCACHEbuffers; _bufferNt++) { \
  110.        if (vfp->CACHEblockN[_bufferNt] == -1) \
  111.      break; \
  112.        else \
  113.      if (vfp->CACHEblockN[_bufferNt] == blockN) { \
  114.        bufferN = _bufferNt; \
  115.        break; \
  116.      } \
  117.     } \
  118.   } \
  119. } \
  120. else \
  121.   bufferN = -1; \
  122. }
  123.  
  124. /******************************************************************************
  125. * Extend the file to a specified number of blocks.
  126. ******************************************************************************/
  127.  
  128. static long EXTENDfile(vfp,toBlockN)
  129. VFILE *vfp;
  130. long toBlockN;
  131. {
  132. long Nbytes;
  133. long blockN;
  134. long bufferNt;
  135. void *buffer;
  136. Nbytes = vfp->PHYeof - nCACHE_BUFFER_BYTEs * vfp->PHYlastBlockN;
  137. if (Nbytes < nCACHE_BUFFER_BYTEs) {
  138.   CACHEbufferN (vfp, vfp->PHYlastBlockN, bufferNt);
  139.   if (bufferNt != -1) {
  140.     WRITE ((nCACHE_BUFFER_BYTEs * vfp->PHYlastBlockN),
  141.        vfp->CACHEbuffers[bufferNt], nCACHE_BUFFER_BYTEs, 1, vfp, 0);
  142.     vfp->CACHEmodified[bufferNt] = FALSE;
  143.   }
  144.   else {
  145.     buffer = (void *) calloc (nCACHE_BUFFER_BYTEs, 1);
  146.     if (buffer == NULL) {
  147.       vfp->error = TRUE;
  148.       return 0;
  149.     }
  150.     READ ((nCACHE_BUFFER_BYTEs * vfp->PHYlastBlockN), buffer, Nbytes, 1, vfp,
  151.       0);
  152.     WRITE ((nCACHE_BUFFER_BYTEs * vfp->PHYlastBlockN), buffer,
  153.        nCACHE_BUFFER_BYTEs, 1, vfp, 0);
  154.     free (buffer);
  155.   }
  156.   vfp->PHYeof = nCACHE_BUFFER_BYTEs * (vfp->PHYlastBlockN + 1);
  157. }
  158. buffer = NULL;
  159. for (blockN = vfp->PHYlastBlockN + 1; blockN <= toBlockN; blockN++) {
  160.    CACHEbufferN (vfp, blockN, bufferNt);
  161.    if (bufferNt != -1) {
  162.      WRITE ((nCACHE_BUFFER_BYTEs * blockN), vfp->CACHEbuffers[bufferNt],
  163.         nCACHE_BUFFER_BYTEs, 1, vfp, 0);
  164.      vfp->CACHEmodified[bufferNt] = FALSE;
  165.    }
  166.    else {
  167.      if (buffer == NULL) {
  168.        buffer = (void *) calloc (nCACHE_BUFFER_BYTEs, 1);
  169.        if (buffer == NULL) {
  170.          vfp->error = TRUE;
  171.          return 0;
  172.        }
  173.      }
  174.      WRITE ((nCACHE_BUFFER_BYTEs * blockN), buffer, nCACHE_BUFFER_BYTEs, 1,
  175.         vfp, 0);
  176.    }
  177.    vfp->PHYlastBlockN = blockN;
  178.    vfp->PHYeof = nCACHE_BUFFER_BYTEs * (blockN + 1);
  179. }
  180. if (buffer != NULL) free (buffer);
  181. return 1;
  182. }
  183.  
  184. /******************************************************************************
  185. * Allocate a cache buffer to use.  It may be necessary to page out a block
  186. * to the file.
  187. ******************************************************************************/
  188.  
  189. static long ALLOCbuffer(vfp,bufferN)
  190. VFILE *vfp;
  191. long *bufferN;
  192. {
  193. long bufferNt;
  194. long oldestAccessedAt;
  195. long Nbytes;
  196. long offset;
  197. long i;
  198.  
  199. *bufferN = -1;
  200.  
  201. /******************************************************************************
  202. * check if there are any unused CACHE buffers - if so, the buffer must be
  203. * allocated (MALLOCed)
  204. ******************************************************************************/
  205.  
  206. for (bufferNt = 0; bufferNt < vfp->nCACHEbuffers; bufferNt++)
  207.    if (vfp->CACHEblockN[bufferNt] == -1) {
  208.      vfp->CACHEbuffers[bufferNt] = (char *) malloc (nCACHE_BUFFER_BYTEs);
  209.      if (vfp->CACHEbuffers[bufferNt] == NULL) {
  210.        vfp->error = TRUE;
  211.        return 0;
  212.      }
  213.      *bufferN = bufferNt;
  214.      break;
  215.    }
  216.  
  217. /******************************************************************************
  218. * if there were no unused buffers, check for the least-recently-used (LRU)
  219. * buffer that has not been modified
  220. ******************************************************************************/
  221.  
  222. if (*bufferN == -1) {
  223.   oldestAccessedAt = vfp->pseudoClock;
  224.   for (bufferNt = 0; bufferNt < vfp->nCACHEbuffers; bufferNt++)
  225.      if ( ! vfp->CACHEmodified[bufferNt])
  226.        if (vfp->CACHEaccessedAt[bufferNt] < oldestAccessedAt) {
  227.      *bufferN = bufferNt;
  228.      oldestAccessedAt = vfp->CACHEaccessedAt[bufferNt];
  229.        }
  230. }
  231.  
  232. /******************************************************************************
  233. * if all buffers have been modified, determine the LRU
  234. ******************************************************************************/
  235.  
  236. if (*bufferN == -1) {
  237.   oldestAccessedAt = vfp->pseudoClock;
  238.   for (bufferNt = 0; bufferNt < vfp->nCACHEbuffers; bufferNt++)
  239.      if (vfp->CACHEaccessedAt[bufferNt] < oldestAccessedAt) {
  240.        *bufferN = bufferNt;
  241.        oldestAccessedAt = vfp->CACHEaccessedAt[bufferNt];
  242.      }
  243. }
  244.  
  245. /******************************************************************************
  246. * if the buffer choosen has been modified, write it out to the file
  247. ******************************************************************************/
  248.  
  249. if (vfp->CACHEmodified[*bufferN]) {
  250.   offset = nCACHE_BUFFER_BYTEs * vfp->CACHEblockN[*bufferN];
  251.   if (offset > vfp->PHYeof)
  252.     if (EXTENDfile (vfp, (vfp->CACHEblockN[*bufferN] - 1)) == 0) return 0;
  253. #if defined(vms)
  254.   Nbytes = nCACHE_BUFFER_BYTEs;
  255. #endif
  256. #if defined(unix) | defined(__MSDOS__)
  257.   Nbytes = Minimum (nCACHE_BUFFER_BYTEs, (vfp->eof - offset));
  258. #endif
  259.   WRITE (offset, vfp->CACHEbuffers[*bufferN], Nbytes, 1, vfp, 0);
  260.   vfp->CACHEmodified[*bufferN] = FALSE;
  261.   vfp->PHYlastBlockN = Maximum (vfp->PHYlastBlockN,
  262.                 vfp->CACHEblockN[*bufferN]);
  263.   vfp->PHYeof = Maximum (vfp->PHYeof,
  264.              ((nCACHE_BUFFER_BYTEs * vfp->CACHEblockN[*bufferN])
  265.                                     + Nbytes));
  266. }
  267.  
  268. /******************************************************************************
  269. * setup the buffer for use
  270. ******************************************************************************/
  271.  
  272. for (i = 0; i < nCACHE_BUFFER_BYTEs; i++) vfp->CACHEbuffers[*bufferN][i] = 0;
  273. vfp->CACHEblockN[*bufferN] = -1;
  274. vfp->CACHEaccessedAt[*bufferN] = -1;
  275.  
  276. return 1;
  277. }
  278.  
  279. /******************************************************************************
  280. * Page in a block from the file.
  281. ******************************************************************************/
  282.  
  283. #define PAGEin(vfp,blockN,bufferN,OnErrorReturn) { \
  284. long _offset; \
  285. long _Nbytes; \
  286. if (ALLOCbuffer(vfp,&bufferN) == 0) return OnErrorReturn; \
  287. _offset = blockN * nCACHE_BUFFER_BYTEs; \
  288. _Nbytes = Minimum (nCACHE_BUFFER_BYTEs, (vfp->PHYeof - _offset)); \
  289. READ (_offset, vfp->CACHEbuffers[bufferN], _Nbytes, 1, vfp, OnErrorReturn); \
  290. vfp->CACHEblockN[bufferN] = blockN; \
  291. vfp->CACHEmodified[bufferN] = FALSE; \
  292. }
  293.  
  294. /******************************************************************************
  295. * Write a block out to the file.
  296. ******************************************************************************/
  297.  
  298. #define WRITEblock(vfp,blockN,buffer,Nbytes,OnErrorReturn) { \
  299. long _offset; \
  300. _offset = nCACHE_BUFFER_BYTEs * blockN; \
  301. if (_offset > vfp->PHYeof) \
  302.   if (EXTENDfile (vfp, (blockN - 1)) == 0) return OnErrorReturn; \
  303. WRITE (_offset, buffer, Nbytes, 1, vfp, OnErrorReturn); \
  304. vfp->PHYlastBlockN = Maximum (vfp->PHYlastBlockN, blockN); \
  305. vfp->PHYeof = Maximum (vfp->PHYeof, (_offset + Nbytes)); \
  306. }
  307.  
  308. /******************************************************************************
  309. * Vopen - open the file and setup V structure.
  310. ******************************************************************************/
  311.  
  312. VFILE *Vopen (file_spec, a_mode, n_buffers)
  313. char    *file_spec;    /* file specification */
  314. char    *a_mode;    /* access mode */
  315. long    n_buffers;    /* number of CACHE buffers to use (0 means use the
  316.                default number) */
  317. {
  318. VFILE    *vfp;        /* pointer to V structure */
  319. int    status;        /* status from I/O function call */
  320. long    bufferN;    /* cache buffer number */
  321.  
  322. #if defined(vms)
  323. char    mrs[10+1];    /* maximum record size */
  324. char    deq[10+1];    /* default allocation quantity */
  325. #endif
  326.  
  327. /******************************************************************************
  328. * allocate V structure (including CACHE buffers)
  329. ******************************************************************************/
  330.  
  331. vfp = (VFILE *) calloc (1, sizeof(VFILE));    /* everything starts at 0 */
  332. if (vfp == NULL) return NULL;
  333.  
  334. vfp->magic_number = VIO_MAGIC_NUMBER;
  335.  
  336. if (n_buffers > 0)
  337.   vfp->nCACHEbuffers = n_buffers;
  338. else
  339.   vfp->nCACHEbuffers = DEFAULT_nCACHE_BUFFERs;
  340.  
  341. vfp->CACHEblockN = (long *) malloc (vfp->nCACHEbuffers * sizeof(long));
  342. if (vfp->CACHEblockN == NULL) {
  343.   FREEvfp (vfp);
  344.   return NULL;
  345. }
  346.  
  347. vfp->CACHEmodified = (long *) malloc (vfp->nCACHEbuffers * sizeof(long));
  348. if (vfp->CACHEmodified == NULL) {
  349.   FREEvfp (vfp);
  350.   return NULL;
  351. }
  352.  
  353. vfp->CACHEaccessedAt = (long *) malloc (vfp->nCACHEbuffers * sizeof(long));
  354. if (vfp->CACHEaccessedAt == NULL) {
  355.   FREEvfp (vfp);
  356.   return NULL;
  357. }
  358.  
  359. vfp->CACHEbuffers = (char **) malloc (vfp->nCACHEbuffers * sizeof(char *));
  360. if (vfp->CACHEbuffers == NULL) {
  361.   FREEvfp (vfp);
  362.   return NULL;
  363. }
  364.  
  365. for (bufferN = 0; bufferN < vfp->nCACHEbuffers; bufferN++) {
  366.    vfp->CACHEbuffers[bufferN] = NULL;
  367. }
  368.  
  369. /******************************************************************************
  370. * open file in fixed length record mode
  371. ******************************************************************************/
  372.  
  373. #if defined(vms)
  374. sprintf (mrs, "mrs=%d", nCACHE_BUFFER_BYTEs);
  375. sprintf (deq, "deq=%d", VMS_DEFAULT_nALLOCATION_BLOCKS);
  376. vfp->fp = fopen (file_spec, a_mode, "rfm=fix", mrs, deq);
  377. #endif
  378.  
  379. #if defined(unix) | defined(__MSDOS__)
  380. vfp->fp = fopen (file_spec, a_mode);
  381. #endif
  382.  
  383. if (vfp->fp == NULL) {
  384.   FREEvfp (vfp);
  385.   return NULL;
  386. }
  387.  
  388. /******************************************************************************
  389. * determine length of file
  390. ******************************************************************************/
  391.  
  392. status = fseek (vfp->fp, 0, SEEK_END);
  393. if (status == EOF) {
  394.   fclose (vfp->fp);
  395.   FREEvfp (vfp);
  396.   return NULL;
  397. }
  398.  
  399. vfp->eof = ftell (vfp->fp);
  400. if (vfp->eof == EOF) {
  401.   fclose (vfp->fp);
  402.   FREEvfp (vfp);
  403.   return NULL;
  404. }
  405.  
  406. vfp->PHYeof = vfp->eof;
  407.  
  408. if (vfp->PHYeof == 0)
  409.   vfp->PHYlastBlockN = -1;
  410. else
  411.   vfp->PHYlastBlockN = (vfp->PHYeof - 1) / nCACHE_BUFFER_BYTEs;
  412.  
  413. /******************************************************************************
  414. * initialize the rest of the V structure 
  415. ******************************************************************************/
  416.  
  417. if (strchr(a_mode,'a') == NULL)
  418.   vfp->offset = 0;
  419. else
  420.   vfp->offset = vfp->eof;
  421.  
  422. vfp->error = FALSE;
  423. vfp->pseudoClock = 1;
  424.  
  425. for (bufferN = 0; bufferN < vfp->nCACHEbuffers; bufferN++) {
  426.    vfp->CACHEblockN[bufferN] = -1;
  427.    vfp->CACHEmodified[bufferN] = FALSE;
  428.    vfp->CACHEaccessedAt[bufferN] = -1;
  429. }
  430.  
  431. vfp->lastBufferNaccessed = -1;
  432.  
  433. /******************************************************************************
  434. * return pointer to V structure
  435. ******************************************************************************/
  436.  
  437. return vfp;
  438. }
  439.  
  440. /******************************************************************************
  441. * Vseek - seek to a position in the file.
  442. ******************************************************************************/
  443.  
  444. int Vseek (vfp, offset, direction)
  445. VFILE    *vfp;        /* pointer to V structure */
  446. long    offset;        /* new read/write offset (position) */
  447. int    direction;    /* reference for offsetting */
  448. {
  449.  
  450. if (vfp->magic_number != VIO_MAGIC_NUMBER) return EOF;
  451. if (vfp->error) return EOF;
  452.  
  453. switch (direction) {
  454.    case SEEK_SET:            /* seek from beginning of file */
  455.     if (offset >= 0) {
  456.       vfp->offset = offset;
  457.       return 0;
  458.     }
  459.     else
  460.       return EOF;
  461.  
  462.    case SEEK_CUR:            /* seek from current offset */
  463.     if (vfp->offset + offset >= 0) {
  464.       vfp->offset += offset;
  465.       return 0;
  466.     }
  467.     else
  468.       return EOF;
  469.  
  470.    case SEEK_END:            /* seek to EOF */
  471.     vfp->offset = vfp->eof;
  472.     return 0;
  473. }
  474.  
  475. return EOF;                /* illegal seek */
  476. }
  477.  
  478. /******************************************************************************
  479. * Vtell - return current offset (position) in file.  This is the byte offset
  480. *      one past the last byte written.
  481. ******************************************************************************/
  482.  
  483. long Vtell (vfp)
  484. VFILE *vfp;        /* pointer to V structure */
  485. {
  486. if (vfp->magic_number != VIO_MAGIC_NUMBER) return EOF;
  487. if (vfp->error) return EOF;
  488.  
  489. return vfp->offset;
  490. }
  491.  
  492. /******************************************************************************
  493. * Veof - check if at EOF.  If so, return non-zero (TRUE).  If not, return zero
  494. *     (FALSE).  This is different that the 'feof' function in that a read at
  495. *     the EOF doesn't have to occur before 'veof' will return TRUE (change
  496. *     to be like 'feof'?).
  497. ******************************************************************************/
  498.  
  499. int Veof (vfp)
  500. VFILE *vfp;        /* pointer to V structure */
  501. {
  502. if (vfp->magic_number != VIO_MAGIC_NUMBER) return FALSE;
  503. if (vfp->error) return FALSE;
  504.  
  505. if (vfp->offset >= vfp->eof)
  506.   return TRUE;
  507. else
  508.   return FALSE;
  509. }
  510.  
  511. /******************************************************************************
  512. * Vread - read from the file.
  513. ******************************************************************************/
  514.  
  515. long Vread (buffer, item_size, n_items, vfp)
  516. void    *buffer;    /* pointer to buffer to read into */
  517. long    item_size;    /* size (in bytes) of each item to read */
  518. long    n_items;    /* number of items to read */
  519. VFILE    *vfp;        /* pointer to V structure */
  520. {
  521. long    Nbytes;        /* total number of bytes in read */
  522. long    firstBlockN;    /* first block involved in read */
  523. long    lastBlockN;    /* last block involved in read */
  524. long    bufferOffset;    /* offset (bytes) into buffer */
  525. long    Xbytes;        /* number of bytes in a transfer */
  526. long    blockN;        /* block number in file (from 0) */
  527. long    bufferN;    /* cache buffer number */
  528.  
  529. if (vfp->magic_number != VIO_MAGIC_NUMBER) return 0;
  530. if (vfp->error) return 0;    /* access not allowed after first error */
  531.  
  532. Nbytes = item_size * n_items;
  533.  
  534. if (Nbytes == 0) return 0;
  535. if (vfp->offset + Nbytes > vfp->eof) return 0;        /* IMPROVE */
  536.  
  537. firstBlockN = vfp->offset / nCACHE_BUFFER_BYTEs;
  538. lastBlockN = (vfp->offset + Nbytes - 1) / nCACHE_BUFFER_BYTEs;
  539.  
  540. bufferOffset = vfp->offset % nCACHE_BUFFER_BYTEs;
  541. Xbytes = Minimum (Nbytes, (nCACHE_BUFFER_BYTEs - bufferOffset));
  542.  
  543. CACHEbufferN (vfp, firstBlockN, bufferN);
  544. if (bufferN == -1) PAGEin (vfp, firstBlockN, bufferN, 0);
  545.  
  546. memmove (buffer, (vfp->CACHEbuffers[bufferN] + bufferOffset), Xbytes);
  547. vfp->CACHEaccessedAt[bufferN] = vfp->pseudoClock++;
  548. vfp->lastBufferNaccessed = bufferN;
  549. buffer = (char *) buffer + Xbytes;
  550.  
  551. for (blockN = firstBlockN + 1; blockN < lastBlockN; blockN++) {
  552.    CACHEbufferN (vfp, blockN, bufferN);
  553.    if (bufferN != -1) {
  554.      memmove (buffer, vfp->CACHEbuffers[bufferN], nCACHE_BUFFER_BYTEs);
  555.      vfp->CACHEaccessedAt[bufferN] = vfp->pseudoClock++;
  556.      vfp->lastBufferNaccessed = bufferN;
  557.    }
  558.    else {
  559.      READ ((nCACHE_BUFFER_BYTEs * blockN), buffer, nCACHE_BUFFER_BYTEs, 1,
  560.        vfp, 0);
  561.    }
  562.    buffer = (char *) buffer + nCACHE_BUFFER_BYTEs;
  563. }
  564.  
  565. if (lastBlockN != firstBlockN) {
  566.   Xbytes = vfp->offset + Nbytes - (nCACHE_BUFFER_BYTEs * lastBlockN);
  567.   CACHEbufferN (vfp, lastBlockN, bufferN);
  568.   if (bufferN == -1) PAGEin (vfp, lastBlockN, bufferN, 0);
  569.   memmove (buffer, vfp->CACHEbuffers[bufferN], Xbytes);
  570.   vfp->CACHEaccessedAt[bufferN] = vfp->pseudoClock++;
  571.   vfp->lastBufferNaccessed = bufferN;
  572. }
  573.  
  574. vfp->offset += Nbytes;
  575.  
  576. return n_items;
  577. }
  578.  
  579. /******************************************************************************
  580. * Vwrite - write to the file.
  581. ******************************************************************************/
  582.  
  583. long Vwrite (buffer, item_size, n_items, vfp)
  584. void    *buffer;    /* pointer to buffer to write from */
  585. long    item_size;    /* size (in bytes) of each item to write */
  586. long    n_items;    /* number of items to write */
  587. VFILE    *vfp;        /* pointer to V structure */
  588. {
  589. long    Nbytes;        /* total number of bytes in write */
  590. long    firstBlockN;    /* first block involved in write */
  591. long    lastBlockN;    /* last block involved in write */
  592. long    bufferOffset;    /* offset (bytes) into buffer */
  593. long    blockN;        /* block number in file (from 0) */
  594. long    Xbytes;        /* number of bytes in a transfer */
  595. long    bufferN;    /* cache buffer number */
  596.  
  597. if (vfp->magic_number != VIO_MAGIC_NUMBER) return 0;
  598. if (vfp->error) return 0;    /* access not allowed after first error */
  599.  
  600. Nbytes = item_size * n_items;
  601.  
  602. if (Nbytes == 0) return 0;
  603.  
  604. firstBlockN = vfp->offset / nCACHE_BUFFER_BYTEs;
  605. lastBlockN = (vfp->offset + Nbytes - 1) / nCACHE_BUFFER_BYTEs;
  606.  
  607. bufferOffset = vfp->offset % nCACHE_BUFFER_BYTEs;
  608. Xbytes = Minimum (Nbytes, (nCACHE_BUFFER_BYTEs - bufferOffset));
  609.  
  610. CACHEbufferN (vfp, firstBlockN, bufferN);
  611. if (bufferN == -1)
  612.   if (firstBlockN <= vfp->PHYlastBlockN) {
  613.     PAGEin (vfp, firstBlockN, bufferN, 0);
  614.   }
  615.   else {
  616.     if (ALLOCbuffer(vfp, &bufferN) == 0) return 0;
  617.     vfp->CACHEblockN[bufferN] = firstBlockN;
  618.   }
  619.  
  620. memmove ((vfp->CACHEbuffers[bufferN] + bufferOffset), buffer, Xbytes);
  621. vfp->CACHEmodified[bufferN] = TRUE;
  622. vfp->CACHEaccessedAt[bufferN] = vfp->pseudoClock++;
  623. vfp->lastBufferNaccessed = bufferN;
  624.  
  625. vfp->eof = Maximum (vfp->eof, (vfp->offset + Xbytes));
  626. buffer = (char *) buffer + Xbytes;
  627.  
  628. for (blockN = firstBlockN + 1; blockN < lastBlockN; blockN++) {
  629.    CACHEbufferN (vfp, blockN, bufferN);
  630.    if (bufferN != -1) {
  631.      memmove (vfp->CACHEbuffers[bufferN], buffer, nCACHE_BUFFER_BYTEs);
  632.      vfp->CACHEmodified[bufferN] = TRUE;
  633.      vfp->CACHEaccessedAt[bufferN] = vfp->pseudoClock++;
  634.      vfp->lastBufferNaccessed = bufferN;
  635.    }
  636.    else {
  637.      WRITEblock (vfp, blockN, buffer, nCACHE_BUFFER_BYTEs, 0);
  638.    }
  639.  
  640.    vfp->eof = Maximum (vfp->eof,
  641.                ((nCACHE_BUFFER_BYTEs * blockN) +
  642.                             nCACHE_BUFFER_BYTEs));
  643.    buffer = (char *) buffer + nCACHE_BUFFER_BYTEs;
  644. }
  645.  
  646. if (lastBlockN != firstBlockN) {
  647.   Xbytes = vfp->offset + Nbytes - (nCACHE_BUFFER_BYTEs * lastBlockN);
  648.  
  649.   CACHEbufferN (vfp, lastBlockN, bufferN);
  650.   if (bufferN == -1)
  651.     if (lastBlockN <= vfp->PHYlastBlockN) {
  652.       PAGEin (vfp, lastBlockN, bufferN, 0);
  653.     }
  654.     else {
  655.       if (ALLOCbuffer(vfp, &bufferN) == 0) return 0;
  656.       vfp->CACHEblockN[bufferN] = lastBlockN;
  657.     }
  658.  
  659.   memmove (vfp->CACHEbuffers[bufferN], buffer, Xbytes);
  660.   vfp->CACHEmodified[bufferN] = TRUE;
  661.   vfp->CACHEaccessedAt[bufferN] = vfp->pseudoClock++;
  662.   vfp->lastBufferNaccessed = bufferN;
  663.  
  664.   vfp->eof = Maximum (vfp->eof, ((nCACHE_BUFFER_BYTEs * lastBlockN) + Xbytes));
  665. }
  666.  
  667. vfp->offset += Nbytes;
  668.  
  669. return n_items;
  670. }
  671.  
  672. /******************************************************************************
  673. * Vclose - close the file.
  674. ******************************************************************************/
  675.  
  676. int Vclose (vfp)
  677. VFILE    *vfp;        /* pointer to V structure */
  678. {
  679. int    status;        /* status code from I/O function call */
  680. long    bufferN;    /* cache buffer number */
  681. long    Nbytes;        /* number of bytes to write */
  682.  
  683. if (vfp->magic_number != VIO_MAGIC_NUMBER) return EOF;
  684.  
  685. /******************************************************************************
  686. * write cache buffer (if no previous errors)
  687. ******************************************************************************/
  688.  
  689. if ( ! vfp->error)
  690.   for (bufferN = 0; bufferN < vfp->nCACHEbuffers; bufferN++)
  691.      if (vfp->CACHEmodified[bufferN]) {
  692. #if defined(vms)
  693.        Nbytes = nCACHE_BUFFER_BYTEs;
  694. #endif
  695. #if defined(unix) | defined(__MSDOS__)
  696.        Nbytes = Minimum (nCACHE_BUFFER_BYTEs,
  697.              (vfp->eof -
  698.                 nCACHE_BUFFER_BYTEs * vfp->CACHEblockN[bufferN]));
  699. #endif
  700.        WRITEblock (vfp, vfp->CACHEblockN[bufferN], vfp->CACHEbuffers[bufferN],
  701.            Nbytes, EOF);
  702.        vfp->CACHEmodified[bufferN] = FALSE;
  703.      }
  704.  
  705. /******************************************************************************
  706. * close the file
  707. ******************************************************************************/
  708.  
  709. status = fclose (vfp->fp);
  710.  
  711. /******************************************************************************
  712. * deallocate V structure
  713. ******************************************************************************/
  714.  
  715. FREEvfp (vfp);
  716.  
  717. /******************************************************************************
  718. * return status of fclose call
  719. ******************************************************************************/
  720.  
  721. return status;
  722. }
  723.